﻿using System;
using System.Runtime.InteropServices;
using System.Security;

// copied from Microsoft.SystemCenter.Advisor.Internal.dll

namespace Microsoft.EnterpriseManagement.Tracing
{
    internal class TraceHelper
    {
        internal static TraceProvider traceProvider;

        static TraceHelper()
        {
            TraceHelper.traceProvider = new TraceProvider("QND.SCOMMM.Provider", new Guid("{E4A69BBA-7AC8-40E1-832A-4B6996291D38}"), true);  //was {530c48ff-4c28-4a25-960d-59f6409f281e}
        }

        public TraceHelper()
        {
        }
    }

    [Guid("748004CA-4959-409a-887C-6546438CF48E")]  //this one seems to be fixed 
    internal class TraceProvider
    {
        private const int maxTraceMessageSize = 8000;

        internal UnsafeNativeMethods.WMIDPREQUEST etwCallback;

        private bool useSequenceNumbers;

        private ulong registrationHandle;

        private ulong traceHandle;

        private byte level;

        private uint flags;

        private bool enabled;

        private Guid controlGuid;

        private string applicationName;

        private TraceProvider.GetTraceLoggerHandle getTraceLoggerHandle;

        private TraceProvider.GetTraceEnableFlags getTraceEnableFlags;

        private TraceProvider.GetTraceEnableLevel getTraceEnableLevel;

        internal string ApplicationName
        {
            get
            {
                return this.applicationName;
            }
        }

        internal int Flags
        {
            get
            {
                return (int)this.flags;
            }
        }

        internal bool IsEnabled
        {
            get
            {
                return this.enabled;
            }
        }

        internal byte Level
        {
            get
            {
                return this.level;
            }
        }

        internal TraceProvider(string applicationName, Guid controlGuid, bool useSequenceNumbers)
        {
            this.applicationName = applicationName;
            this.controlGuid = controlGuid;
            this.useSequenceNumbers = useSequenceNumbers;
            IntPtr moduleHandle = UnsafeNativeMethods.GetModuleHandle("advapi32.dll");
            IntPtr procAddress = UnsafeNativeMethods.GetProcAddress(moduleHandle, "GetTraceLoggerHandle");
            this.getTraceLoggerHandle = (TraceProvider.GetTraceLoggerHandle)Marshal.GetDelegateForFunctionPointer(procAddress, typeof(TraceProvider.GetTraceLoggerHandle));
            procAddress = UnsafeNativeMethods.GetProcAddress(moduleHandle, "GetTraceEnableFlags");
            this.getTraceEnableFlags = (TraceProvider.GetTraceEnableFlags)Marshal.GetDelegateForFunctionPointer(procAddress, typeof(TraceProvider.GetTraceEnableFlags));
            procAddress = UnsafeNativeMethods.GetProcAddress(moduleHandle, "GetTraceEnableLevel");
            this.getTraceEnableLevel = (TraceProvider.GetTraceEnableLevel)Marshal.GetDelegateForFunctionPointer(procAddress, typeof(TraceProvider.GetTraceEnableLevel));
            this.Register();
        }

        ~TraceProvider()
        {
            UnsafeNativeMethods.UnregisterTraceGuids(this.registrationHandle);
            GC.KeepAlive(this.etwCallback);
        }

        internal static int GetBufferSize(int numberOfFields, int totalParameterSize)
        {
            return (int)(Marshal.SizeOf(typeof(UnsafeNativeMethods.VALIST_HEADER)) + (numberOfFields + 1) * Marshal.SizeOf(typeof(UnsafeNativeMethods.VALIST_FIELD)) + totalParameterSize);
        }

        internal static unsafe void InitializeTraceBuffer(byte* buffer, Guid messageGuid, int messageNumber)
        {
            UnsafeNativeMethods.VALIST_HEADER* vALISTHEADERPointer = (UnsafeNativeMethods.VALIST_HEADER*)buffer;
            (*vALISTHEADERPointer).MessageGuid = messageGuid;
            (*vALISTHEADERPointer).MessageNumber = (ushort)messageNumber;
            (*vALISTHEADERPointer).NumberOfFields = 0;
            UnsafeNativeMethods.VALIST_FIELD* vALISTFIELDPointer = (UnsafeNativeMethods.VALIST_FIELD*)(buffer + sizeof(UnsafeNativeMethods.VALIST_HEADER));
            (*vALISTFIELDPointer).DataPointer = null;
            (*vALISTFIELDPointer).DataLength = 0;
        }

        internal static unsafe void* InitializeTraceBuffer(byte* buffer, Guid messageGuid, int messageNumber, int numberOfFields, ref int dataBufferOffset)
        {
            UnsafeNativeMethods.VALIST_HEADER* vALISTHEADERPointer = (UnsafeNativeMethods.VALIST_HEADER*)buffer;
            (*vALISTHEADERPointer).MessageGuid = messageGuid;
            (*vALISTHEADERPointer).MessageNumber = (ushort)messageNumber;
            (*vALISTHEADERPointer).NumberOfFields = (ushort)numberOfFields;
            UnsafeNativeMethods.VALIST_FIELD* vALISTFIELDPointer = (UnsafeNativeMethods.VALIST_FIELD*)(buffer + sizeof(UnsafeNativeMethods.VALIST_HEADER));
            UnsafeNativeMethods.VALIST_FIELD* vALISTFIELDPointer1 = vALISTFIELDPointer + numberOfFields * sizeof(UnsafeNativeMethods.VALIST_FIELD);
            (*vALISTFIELDPointer1).DataPointer = null;
            (*vALISTFIELDPointer1).DataLength = 0;
            byte* numPointer = (byte*)(vALISTFIELDPointer1 + sizeof(UnsafeNativeMethods.VALIST_FIELD));
            dataBufferOffset = (int)((long)((numPointer - buffer) / 1));
            return vALISTFIELDPointer;
        }

        internal static unsafe void* InitializeTraceField(void* field, char* charBuffer, int length, byte* buffer, ref int dataBufferOffset)
        {
            byte* numPointer = (byte*)(buffer + dataBufferOffset);
            *numPointer = (byte)(length * 2);
            dataBufferOffset = dataBufferOffset + 2;
            UnsafeNativeMethods.VALIST_FIELD* vALISTFIELDPointer = (UnsafeNativeMethods.VALIST_FIELD*)field;
            (*vALISTFIELDPointer).DataLength = 2;
            (*vALISTFIELDPointer).DataPointer = (void*)numPointer;
            vALISTFIELDPointer = vALISTFIELDPointer + sizeof(UnsafeNativeMethods.VALIST_FIELD);
            (*vALISTFIELDPointer).DataLength = (uint)(length * 2);
            (*vALISTFIELDPointer).DataPointer = (void*)charBuffer;
            return vALISTFIELDPointer + sizeof(UnsafeNativeMethods.VALIST_FIELD);
        }

        internal static unsafe void* InitializeTraceField(void* field, byte* byteBuffer, int length, byte* buffer, ref int dataBufferOffset)
        {
            byte* numPointer = (byte*)(buffer + dataBufferOffset);
            *numPointer = (byte)length;
            dataBufferOffset = dataBufferOffset + 2;
            UnsafeNativeMethods.VALIST_FIELD* vALISTFIELDPointer = (UnsafeNativeMethods.VALIST_FIELD*)field;
            (*vALISTFIELDPointer).DataLength = 2;
            (*vALISTFIELDPointer).DataPointer = (void*)numPointer;
            vALISTFIELDPointer = vALISTFIELDPointer + sizeof(UnsafeNativeMethods.VALIST_FIELD);
            (*vALISTFIELDPointer).DataLength = (uint)length;
            (*vALISTFIELDPointer).DataPointer = (void*)byteBuffer;
            return vALISTFIELDPointer + sizeof(UnsafeNativeMethods.VALIST_FIELD);
        }

        internal static unsafe void* InitializeTraceField(void* field, char value, byte* buffer, ref int dataBufferOffset)
        {
            byte* numPointer = (byte*)(buffer + dataBufferOffset);
            *numPointer = (byte)value;
            dataBufferOffset = dataBufferOffset + 2;
            UnsafeNativeMethods.VALIST_FIELD* vALISTFIELDPointer = (UnsafeNativeMethods.VALIST_FIELD*)field;
            (*vALISTFIELDPointer).DataLength = 2;
            (*vALISTFIELDPointer).DataPointer = (void*)numPointer;
            return vALISTFIELDPointer + sizeof(UnsafeNativeMethods.VALIST_FIELD);
        }

        internal static unsafe void* InitializeTraceField(void* field, byte value, void* buffer, ref int dataBufferOffset)
        {
            byte* numPointer = (byte*)((byte*)buffer + dataBufferOffset);
            *numPointer = value;
            dataBufferOffset = dataBufferOffset + 1;
            UnsafeNativeMethods.VALIST_FIELD* vALISTFIELDPointer = (UnsafeNativeMethods.VALIST_FIELD*)field;
            (*vALISTFIELDPointer).DataLength = 1;
            (*vALISTFIELDPointer).DataPointer = (void*)numPointer;
            return vALISTFIELDPointer + sizeof(UnsafeNativeMethods.VALIST_FIELD);
        }

        internal static unsafe void* InitializeTraceField(void* field, short value, void* buffer, ref int dataBufferOffset)
        {
            byte* numPointer = (byte*)((byte*)buffer + dataBufferOffset);
            *numPointer = (byte)value;
            dataBufferOffset = dataBufferOffset + 2;
            UnsafeNativeMethods.VALIST_FIELD* vALISTFIELDPointer = (UnsafeNativeMethods.VALIST_FIELD*)field;
            (*vALISTFIELDPointer).DataLength = 2;
            (*vALISTFIELDPointer).DataPointer = (void*)numPointer;
            return vALISTFIELDPointer + sizeof(UnsafeNativeMethods.VALIST_FIELD);
        }

        internal static unsafe void* InitializeTraceField(void* field, ushort value, void* buffer, ref int dataBufferOffset)
        {
            byte* numPointer = (byte*)((byte*)buffer + dataBufferOffset);
            *numPointer = (byte) value;
            dataBufferOffset = dataBufferOffset + 2;
            UnsafeNativeMethods.VALIST_FIELD* vALISTFIELDPointer = (UnsafeNativeMethods.VALIST_FIELD*)field;
            (*vALISTFIELDPointer).DataLength = 2;
            (*vALISTFIELDPointer).DataPointer = (void*)numPointer;
            return vALISTFIELDPointer + sizeof(UnsafeNativeMethods.VALIST_FIELD);
        }


        internal static unsafe void* InitializeTraceField(void* field, int value, void* buffer, ref int dataBufferOffset)
        {
            byte* numPointer = (byte*)((byte*)buffer + dataBufferOffset);
            *numPointer = (byte)value;
            dataBufferOffset = dataBufferOffset + 4;
            UnsafeNativeMethods.VALIST_FIELD* vALISTFIELDPointer = (UnsafeNativeMethods.VALIST_FIELD*)field;
            (*vALISTFIELDPointer).DataLength = 4;
            (*vALISTFIELDPointer).DataPointer = (void*)numPointer;
            return vALISTFIELDPointer + sizeof(UnsafeNativeMethods.VALIST_FIELD);
        }

        internal static unsafe void* InitializeTraceField(void* field, uint value, void* buffer, ref int dataBufferOffset)
        {
            byte* numPointer = (byte*)((byte*)buffer + dataBufferOffset);
            *numPointer = (byte)value;
            dataBufferOffset = dataBufferOffset + 4;
            UnsafeNativeMethods.VALIST_FIELD* vALISTFIELDPointer = (UnsafeNativeMethods.VALIST_FIELD*)field;
            (*vALISTFIELDPointer).DataLength = 4;
            (*vALISTFIELDPointer).DataPointer = (void*)numPointer;
            return vALISTFIELDPointer + sizeof(UnsafeNativeMethods.VALIST_FIELD);
        }

        internal static unsafe void* InitializeTraceField(void* field, IntPtr value, byte* buffer, ref int dataBufferOffset)
        {
            byte* numPointer = (byte*)(buffer + dataBufferOffset);
            *numPointer = (byte)value;
            dataBufferOffset = (int)(dataBufferOffset + sizeof(IntPtr));
            UnsafeNativeMethods.VALIST_FIELD* vALISTFIELDPointer = (UnsafeNativeMethods.VALIST_FIELD*)field;
            (*vALISTFIELDPointer).DataLength = (uint)sizeof(IntPtr);
            (*vALISTFIELDPointer).DataPointer = (void*)numPointer;
            return vALISTFIELDPointer + sizeof(UnsafeNativeMethods.VALIST_FIELD);
        }

   
        internal static unsafe void* InitializeTraceField(void* field, long value, void* buffer, ref int dataBufferOffset)
        {
            byte* numPointer = (byte*)((byte*)buffer + dataBufferOffset);
            *numPointer = (byte)value;
            dataBufferOffset = dataBufferOffset + 8;
            UnsafeNativeMethods.VALIST_FIELD* vALISTFIELDPointer = (UnsafeNativeMethods.VALIST_FIELD*)field;
            (*vALISTFIELDPointer).DataLength = 8;
            (*vALISTFIELDPointer).DataPointer = (void*)numPointer;
            return vALISTFIELDPointer + sizeof(UnsafeNativeMethods.VALIST_FIELD);
        }

        internal static unsafe void* InitializeTraceField(void* field, ulong value, void* buffer, ref int dataBufferOffset)
        {
            byte* numPointer = (byte*)((byte*)buffer + dataBufferOffset);
            *numPointer = (byte)value;
            dataBufferOffset = dataBufferOffset + 8;
            UnsafeNativeMethods.VALIST_FIELD* vALISTFIELDPointer = (UnsafeNativeMethods.VALIST_FIELD*)field;
            (*vALISTFIELDPointer).DataLength = 8;
            (*vALISTFIELDPointer).DataPointer = (void*)numPointer;
            return vALISTFIELDPointer + sizeof(UnsafeNativeMethods.VALIST_FIELD);
        }

        internal static unsafe void* InitializeTraceField(void* field, double value, void* buffer, ref int dataBufferOffset)
        {
            byte* numPointer = (byte*)((byte*)buffer + dataBufferOffset);
            *numPointer = (byte)value;
            dataBufferOffset = dataBufferOffset + 8;
            UnsafeNativeMethods.VALIST_FIELD* vALISTFIELDPointer = (UnsafeNativeMethods.VALIST_FIELD*)field;
            (*vALISTFIELDPointer).DataLength = 8;
            (*vALISTFIELDPointer).DataPointer = (void*)numPointer;
            return vALISTFIELDPointer + sizeof(UnsafeNativeMethods.VALIST_FIELD);
        }

        internal static unsafe void* InitializeTraceField(void* field, Guid value, void* buffer, ref int dataBufferOffset)
        {
            byte* numPointer = (byte*)((byte*)buffer + dataBufferOffset);
            byte[] guid = value.ToByteArray();
            for (int i = 0; i < 16; i++) { *numPointer++ = guid[i]; }
            //*numPointer = (byte*)&value;
            dataBufferOffset = (int)(dataBufferOffset + sizeof(Guid));
            UnsafeNativeMethods.VALIST_FIELD* vALISTFIELDPointer = (UnsafeNativeMethods.VALIST_FIELD*)field;
            (*vALISTFIELDPointer).DataLength = (uint)sizeof(Guid);
            (*vALISTFIELDPointer).DataPointer = (void*)numPointer;
            return vALISTFIELDPointer + sizeof(UnsafeNativeMethods.VALIST_FIELD);
        }

        internal static unsafe void* InitializeTraceField(void* field, DateTime value, void* buffer, ref int dataBufferOffset)
        {
            byte* ticks = (byte*)((byte*)buffer + dataBufferOffset);
            *ticks = (byte)value.Ticks;
            dataBufferOffset = dataBufferOffset + 8;
            UnsafeNativeMethods.VALIST_FIELD* vALISTFIELDPointer = (UnsafeNativeMethods.VALIST_FIELD*)field;
            (*vALISTFIELDPointer).DataLength = 8;
            (*vALISTFIELDPointer).DataPointer = (void*)ticks;
            return vALISTFIELDPointer + sizeof(UnsafeNativeMethods.VALIST_FIELD);
        }

        internal static string MakeStringArg(object arg)
        {
            string str = null;
            if (arg != null)
            {
                str = arg.ToString();
            }
            if (!string.IsNullOrEmpty(str))
            {
                return str;
            }
            return "NULL";
        }

        internal static long MakeTimeStampArg(object arg)
        {
            long num;
            if (arg == null)
            {
                return (long)0;
            }
            if (!(arg is DateTime))
            {
                try
                {
                    num = Convert.ToInt64(arg);
                }
                catch (InvalidCastException invalidCastException)
                {
                    num = (long)0;
                }
            }
            else
            {
                try
                {
                    num = (((DateTime)arg).Equals(DateTime.MinValue) ? (long)0 : ((DateTime)arg).ToFileTime());
                }
                catch (ArgumentOutOfRangeException argumentOutOfRangeException)
                {
                    num = (long)0;
                }
            }
            return num;
        }

        private unsafe uint MyCallback(UnsafeNativeMethods.WMIDPREQUESTCODE requestCode, IntPtr context, uint* bufferSize, byte* byteBuffer)
        {
            UnsafeNativeMethods.WNODE_HEADER* wNODEHEADERPointer = (UnsafeNativeMethods.WNODE_HEADER*)byteBuffer;
            switch (requestCode)
            {
                case UnsafeNativeMethods.WMIDPREQUESTCODE.WMI_ENABLE_EVENTS:
                    {
                        this.traceHandle = this.getTraceLoggerHandle(wNODEHEADERPointer);
                        this.flags = this.getTraceEnableFlags(this.traceHandle);
                        this.level = this.getTraceEnableLevel(this.traceHandle);
                        this.enabled = true;
                        break;
                    }
                case UnsafeNativeMethods.WMIDPREQUESTCODE.WMI_DISABLE_EVENTS:
                    {
                        this.enabled = false;
                        this.traceHandle = (ulong)0;
                        this.level = 0;
                        this.flags = 0;
                        break;
                    }
                default:
                    {
                        this.enabled = false;
                        this.traceHandle = (ulong)0;
                        break;
                    }
            }
            return (uint)0;
        }

        private uint Register()
        {
            unsafe
            {
                this.etwCallback = new UnsafeNativeMethods.WMIDPREQUEST(this.MyCallback);
                UnsafeNativeMethods.TRACE_GUID_REGISTRATION zero = new UnsafeNativeMethods.TRACE_GUID_REGISTRATION();
                Guid guid = new Guid("{5BC62AA8-0F6E-490E-B9FF-6C45F527D7C4}");  //was {b4955bf0-3af1-4740-b475-99055d3fe9aa}
                zero.Guid = &guid;
                zero.RegHandle = IntPtr.Zero;
                return UnsafeNativeMethods.RegisterTraceGuids(this.etwCallback, null, ref this.controlGuid, 1, ref zero, null, null, out this.registrationHandle);
            }
        }

        internal unsafe uint TraceEvent(void* buffer)
        {
            int i;
            UnsafeNativeMethods.TRACE_MESSAGE_FLAGS tRACEMESSAGEFLAG = UnsafeNativeMethods.TRACE_MESSAGE_FLAGS.TRACE_MESSAGE_GUID | UnsafeNativeMethods.TRACE_MESSAGE_FLAGS.TRACE_MESSAGE_TIMESTAMP | UnsafeNativeMethods.TRACE_MESSAGE_FLAGS.TRACE_MESSAGE_SYSTEMINFO;
            if (this.useSequenceNumbers)
            {
                tRACEMESSAGEFLAG = tRACEMESSAGEFLAG | UnsafeNativeMethods.TRACE_MESSAGE_FLAGS.TRACE_MESSAGE_SEQUENCE;
            }
            UnsafeNativeMethods.VALIST_HEADER* vALISTHEADERPointer = (UnsafeNativeMethods.VALIST_HEADER*)buffer;
            UnsafeNativeMethods.VALIST_FIELD* vALISTFIELDPointer = (UnsafeNativeMethods.VALIST_FIELD*)(vALISTHEADERPointer + sizeof(UnsafeNativeMethods.VALIST_HEADER));
            int dataLength = (int)((long)(((byte*)buffer - (byte*)vALISTFIELDPointer) / 1) + (long)(((*vALISTHEADERPointer).NumberOfFields + 1) * sizeof(UnsafeNativeMethods.VALIST_FIELD)));
            for (i = 0; i < (*vALISTHEADERPointer).NumberOfFields; i++)
            {
                if ((*vALISTFIELDPointer).DataLength < 512)
                {
                    dataLength = (int)(dataLength + (*vALISTFIELDPointer).DataLength);
                }
                vALISTFIELDPointer = vALISTFIELDPointer + sizeof(UnsafeNativeMethods.VALIST_FIELD);
            }
            vALISTFIELDPointer = (UnsafeNativeMethods.VALIST_FIELD*)(vALISTHEADERPointer + sizeof(UnsafeNativeMethods.VALIST_HEADER));
            for (i = 0; i < (*vALISTHEADERPointer).NumberOfFields; i++)
            {
                if ((*vALISTFIELDPointer).DataLength >= 512)
                {
                    if ((ulong)(*vALISTFIELDPointer).DataLength + (ulong)dataLength >= (ulong)8000)
                    {
                        (*vALISTFIELDPointer).DataLength = (uint)(8000 - dataLength);
                    }
                    dataLength = (int)(dataLength + (*vALISTFIELDPointer).DataLength);
                }
                vALISTFIELDPointer = vALISTFIELDPointer + sizeof(UnsafeNativeMethods.VALIST_FIELD);
            }
            return UnsafeNativeMethods.TraceMessageVa(this.traceHandle, (uint)tRACEMESSAGEFLAG, &(*vALISTHEADERPointer).MessageGuid, (*vALISTHEADERPointer).MessageNumber, vALISTHEADERPointer + sizeof(UnsafeNativeMethods.VALIST_HEADER));
        }

        [SuppressUnmanagedCodeSecurity]
        private delegate uint GetTraceEnableFlags(ulong TraceHandle);

        [SuppressUnmanagedCodeSecurity]
        private delegate byte GetTraceEnableLevel(ulong TraceHandle);

        [SuppressUnmanagedCodeSecurity]
        private unsafe delegate ulong GetTraceLoggerHandle(UnsafeNativeMethods.WNODE_HEADER* Buffer);

        internal enum TraceLevel : byte
        {
            TRACE_LEVEL_FATAL = 1,
            TRACE_LEVEL_ERROR = 2,
            TRACE_LEVEL_WARN = 3,
            TRACE_LEVEL_INFO = 4,
            TRACE_LEVEL_PERFORMANCE = 5,
            TRACE_LEVEL_VERBOSE = 6
        }
    }

    internal sealed class UnsafeNativeMethods
    {
        internal const int TRACE_MESSAGE_MAXIMUM_SIZE = 8192;

        internal const uint ERROR_INVALID_PARAMETER = 87;

        internal UnsafeNativeMethods()
        {
        }

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, EntryPoint = "GetModuleHandleW", ExactSpelling = false)]
        [SuppressUnmanagedCodeSecurity]
        internal static extern IntPtr GetModuleHandle([In] string lpModuleName);

        [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = false)]
        [SuppressUnmanagedCodeSecurity]
        internal static extern IntPtr GetProcAddress([In] IntPtr hModule, [In] string lpProcName);

        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "RegisterTraceGuidsW", ExactSpelling = false)]
        [SuppressUnmanagedCodeSecurity]
        internal static extern unsafe uint RegisterTraceGuids([In] UnsafeNativeMethods.WMIDPREQUEST RequestAddress, [In] void* RequestContext, [In] ref Guid ControlGuid, [In] uint GuidCount, ref UnsafeNativeMethods.TRACE_GUID_REGISTRATION TraceGuidReg, [In] string MofImagePath, [In] string MofResourceName, out ulong RegistrationHandle);

        [DllImport("advapi32.dll", CharSet = CharSet.None, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        internal static extern unsafe uint TraceEvent(ulong TraceHandle, UnsafeNativeMethods.EVENT_TRACE_BUFFER* EventTrace);

        [DllImport("advapi32.dll", CharSet = CharSet.None, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        internal static extern unsafe uint TraceMessageVa(ulong TraceHandle, uint MessageFlags, Guid* MessageGuid, ushort MessageNumber, void* MessageArgList);

        [DllImport("advapi32.dll", CharSet = CharSet.None, ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        internal static extern int UnregisterTraceGuids(ulong RegistrationHandle);

        [StructLayout(LayoutKind.Explicit)]
        internal struct EVENT_TRACE_BUFFER
        {
            [FieldOffset(0)]
            internal uint BufferSize;

            [FieldOffset(4)]
            internal uint ProviderId;

            [FieldOffset(8)]
            internal uint ThreadId;

            [FieldOffset(12)]
            internal uint ProcessId;

            [FieldOffset(16)]
            internal long TimeStamp;

            [FieldOffset(24)]
            internal Guid Guid;

            [FieldOffset(40)]
            internal uint ClientContext;

            [FieldOffset(44)]
            internal uint Flags;

            [FieldOffset(48)]
            internal UnsafeNativeMethods.MOF_FIELD UserData;
        }

        [StructLayout(LayoutKind.Explicit)]
        internal struct MOF_FIELD
        {
            [FieldOffset(0)]
            internal ulong ZeroInit;

            [FieldOffset(0)]
            internal unsafe void* DataPointer;

            [FieldOffset(8)]
            internal uint DataLength;

            [FieldOffset(12)]
            internal uint DataType;
        }

        internal struct TRACE_GUID_REGISTRATION
        {
            internal unsafe Guid* Guid;

            internal IntPtr RegHandle;
        }

        [Flags]
        internal enum TRACE_MESSAGE_FLAGS : uint
        {
            TRACE_MESSAGE_SEQUENCE = 1,
            TRACE_MESSAGE_GUID = 2,
            TRACE_MESSAGE_COMPONENTID = 4,
            TRACE_MESSAGE_TIMESTAMP = 8,
            TRACE_MESSAGE_PERFORMANCE_TIMESTAMP = 16,
            TRACE_MESSAGE_SYSTEMINFO = 32
        }

        internal struct VALIST_FIELD
        {
            internal unsafe void* DataPointer;

            internal uint DataLength;
        }

        [StructLayout(LayoutKind.Explicit)]
        internal struct VALIST_HEADER
        {
            [FieldOffset(0)]
            internal Guid MessageGuid;

            [FieldOffset(16)]
            internal ushort MessageNumber;

            [FieldOffset(18)]
            internal ushort NumberOfFields;
        }

        internal unsafe delegate uint WMIDPREQUEST(UnsafeNativeMethods.WMIDPREQUESTCODE RequestCode, IntPtr RequestContext, uint* BufferSize, byte* Buffer);

        internal enum WMIDPREQUESTCODE : uint
        {
            WMI_ENABLE_EVENTS = 4,
            WMI_DISABLE_EVENTS = 5
        }

        internal enum WNODE_FLAGS : uint
        {
            WNODE_FLAG_TRACED_GUID = 131072,
            WNODE_FLAG_USE_GUID_PTR = 524288,
            WNODE_FLAG_USE_MOF_PTR = 1048576
        }

        [StructLayout(LayoutKind.Explicit)]
        internal struct WNODE_HEADER
        {
            [FieldOffset(0)]
            internal uint BufferSize;

            [FieldOffset(4)]
            internal uint ProviderId;

            [FieldOffset(8)]
            internal IntPtr HistoricalContext;

            [FieldOffset(16)]
            internal long TimeStamp;

            [FieldOffset(24)]
            internal Guid Guid;

            [FieldOffset(40)]
            internal uint ClientContext;

            [FieldOffset(44)]
            internal uint Flags;
        }
    }
}